/**
 * 阿里云OSS上传
 */
import OSS from 'ali-oss';
import * as fs from 'node:fs';
import * as path from 'node:path';

const prefix = 'images'; // 阿里云上传后的文件夹
const toUpload = ['.images']; // 本地应上传到阿里云的文件夹

// OSS相关的权限配置和bucket地址
const client = new OSS({
    region: 'oss-cn-hangzhou',
    accessKeyId: 'LTAI5tMizqXWkZuBM8woemdu',
    accessKeySecret: 'fmZvd3ycsxtvKnB8HOW6l9IkR8gZX8',
    bucket: 'xdclass-cdn-images',
});

/**
 * 上传文件到阿里云OSS
 */
async function uploadImagesToOss() {
    // 判断本地目录是否存在的容错处理
    if (isLocalDirExists().length === 0) {
        throw new Error('本地打包目录不存在');
    }
    // 先删除阿里云的文件
    console.log('正在删除...');
    await delDirs()
        .then(() => {
            console.log('删除成功！');
        })
        .catch((err) => {
            throw new Error('删除失败:', err);
        });

    // 删除完成后上传文件
    console.log('正在上传...');
    await addFileToOSSSync(isLocalDirExists()[0], `${prefix}/`)
        .then(() => {
            console.log('oss上传成功!');
        })
        .catch((err) => {
            throw new Error('上传oss失败:', err);
        });
}

/**
 * 递归删除全部的文件（层级递归子目录）
 * @param p 要删除的文件夹名称
 */
async function delDirs(p: string = `${prefix}/`) {
    // 遍历出最初的文件列表
    let files = await client.list(
        {
            prefix: p,
            delimiter: '/',
            'max-keys': '1000',
        },
        {}
    );
    // 如果目录下存在子目录的情况下 继续递归删除子目录
    if (files.prefixes && files.prefixes.length > 0) {
        await Promise.all(files.prefixes.map(async (p) => await delDirs(p)));
    }

    // 删除当前目录下的所有文件
    await Promise.all(files.objects.map(async (o) => await handleDel(o.name)));
}

/**
 * 判断当前文件是否存在
 */
function isLocalDirExists() {
    return toUpload.filter((item) => fs.existsSync(item));
}

/**
 * 将文件上传到OSS中
 * @param src 本地目录
 * @param prefix 上传OSS的目录
 */
async function addFileToOSSSync(src: string, prefix: string) {
    // 读取出本地目录的全部文件
    let imgs = fs.readdirSync(src);
    // 递归目录逐个上传
    await Promise.all(
        imgs.map(async (item) => {
            // 输出待上传的规范的路径
            let img = path.join(src, item);
            // 返回文件路径相关信息
            let st = fs.statSync(img);

            // 如果img是个目录则需要二次递归 否则则上传
            if (st.isFile() && item !== '.DS_Store') {
                await putOSS(img, path.join(prefix, item));
            } else if (st.isDirectory()) {
                addFileToOSSSync(img, path.join(prefix, item) + '/');
            }
        })
    );
}

/**
 * 上传文件的具体方法
 * @param img 具体上传文件的本地图片位置
 * @param uploadName 上传后的相对路径和文件名
 */
async function putOSS(img: string, uploadName: string) {
    try {
        await client.put(uploadName, img);
    } catch (err) {
        throw new Error('上传失败:', err);
    }
}

/**
 * 具体的删除文件
 * @param name 待删除的文件名称
 */
async function handleDel(name: string) {
    try {
        await client.delete(name);
    } catch (err) {
        err.failObjectName = name;
        return err;
    }
}

// 执行
uploadImagesToOss();

